/* ========================================================================
                                GLOBAL VARIABLES
   ======================================================================== */
var shipPartWidth = 20;


/* ========================================================================
                                Classes
   ======================================================================== */

/* ========================================================================
                                Block
   ======================================================================== */

function hasBlockClass(className) { return this.dom.hasClass(className); }
function addBlockClass(add) { this.dom.addClass(add); }
function removeBlockClass(add) { this.dom.removeClass(add); }
function changeBlockClass(add, remove) { if (remove != undefined) this.removeCss(remove); this.addCss(add); }
function getBlockClass() { return this.dom.attr('class'); }
function changeBlockStyle(css) { this.dom.css(css); }

function block(className, posX, posY) {
    this.dom = $('<div />').addClass('ship-part');
    if (className != undefined) this.dom.addClass(className);
    this.x = posX || 0;
    this.y = posY || 0;
    this.dom.css({ left: numToPer(posX * 100), top: numToPer(posY * 100) });
}
block.prototype.changeCss = changeBlockClass;
block.prototype.addCss = addBlockClass;
block.prototype.removeCss = removeBlockClass;
block.prototype.hasCss = hasBlockClass;
block.prototype.getCss = getBlockClass;
block.prototype.style = changeBlockStyle;


/* ========================================================================
                                Block List
   ======================================================================== */

function makeBlockItem(x) { if (this.array[x] == undefined) this.array[x] = []; }
function getBlockItem(x, y) { this.make(x); return this.array[x][y]; }
function pushBlockItem(item) { this.make(item.x); this.array[item.x][item.y] = item; this.list.push(item); }
function popBlockItem(x, y) { var item = this.get(x, y); this.list.pop(item); this.array[x][y] = undefined; return item; }
function isEmptyBlockItem(x, y) { return this.get(x, y) == undefined; }

function blockList() {
    this.array = [];
    this.list = [];
}
blockList.prototype.make = makeBlockItem;
blockList.prototype.get = getBlockItem;
blockList.prototype.push = pushBlockItem;
blockList.prototype.pop = popBlockItem;
blockList.prototype.empty = isEmptyBlockItem;


/* ========================================================================
                                Ship
   ======================================================================== */

function loadShipBlocks(blockData) {
    var data; var obj;
    for (var i = 0; i < blockData.length; i++) {
        data = blockData[i];
        obj = this.blocks.get(data.x, data.y);
        obj.changeCss('ship-block', 'ship-spot');
        if (data.c != undefined) obj.addCss(data.c);
        this.addSpots(obj.x, obj.y);
    }
    data = undefined; obj = undefined;
}
function loadShipBox() { this.start.style({ left: this.left + '%', top: this.top + '%' }); $('.box').append(this.start.dom); }
function newShipBlock(className, x, y) { var obj = new block(className, x, y); this.blocks.push(obj); return obj; }
function newSpotBlock(x, y) { if (this.blocks.empty(x, y)) this.start.dom.append(this.newBlock('ship-spot', x, y).dom); }
function newSpotBlocks(x, y) { this.addSpot(x + 1, y); this.addSpot(x - 1, y); this.addSpot(x, y + 1); this.addSpot(x, y - 1); }
function getShipBlockFromHtml(div) {
    var x = perToNum(div.style.left) / 100;
    var y = perToNum(div.style.top) / 100;
    return this.blocks.get(x, y);
}
function changeSpotToBlock(div) {
    var obj = this.getBlockFromDiv(div);
    obj.changeCss('ship-block', 'ship-spot');
    this.addSpots(obj.x, obj.y);
}
function changeShipBlock(div) {
    var obj = this.getBlockFromDiv(div);
    if (obj.hasCss('green')) obj.changeCss('blue', 'green');
    else if (obj.hasCss('blue')) obj.changeCss('yellow', 'blue');
    else if (obj.hasCss('yellow')) obj.removeCss('yellow');
    else if (obj.hasCss('red')) return;
    else obj.addCss('green');
}
function moveShipLeft() { this.degree -= 10; this.start.style({ "transform": "rotate(" + this.degree + "deg)" }); }
function moveShipRight() { this.degree += 10; this.start.style({ "transform": "rotate(" + this.degree + "deg)" }); }
function moveShipUp() {
    var rads = toRadians(this.degree);
    this.top -= (Math.cos(rads) * 1.5);
    this.left += (Math.sin(rads) * 1.5);
    //$('.box').css({ "left": numToPer(this.left), "margin-top": numToPer(this.top) });
    $('.ship-start.active').css({ "left": numToPer(this.left), "top": numToPer(this.top) });
}
function moveShipDown() {
    var rads = toRadians(this.degree);
    this.top += (Math.cos(rads) * 1.5);
    this.left -= (Math.sin(rads) * 1.5);
    $('.ship-start.active').css({ "left": numToPer(this.left), "top": numToPer(this.top) });
}
function createShipProjetile(e, size) {
    //this.spacebar = false;

    if (this.start.getCss() == e.target.className) return;
    if (this.start.getCss() == e.target.parentNode.className) return;

    var bPos = $('.box').position();
    var x = e.pageX - bPos.left;
    var y = e.pageY + bPos.top;
    var sPos = this.start.dom.position();

    var gunBlock = {};
    for (var i = 0; i < this.blocks.list.length; i++) {
        gunBlock = this.blocks.list[i];
        if(gunBlock.hasCss("yellow"))
        {
            var gSLeft = (gunBlock.x * size);
            var gSTop = (gunBlock.y * size);
            var gLeft = sPos.left - gSLeft;
            var gTop = sPos.top + gSTop;
            var deltaY = y - gTop;
            var deltaX = x - gLeft;
            var rads = Math.atan(deltaY / deltaX);
            var degree = rads * 180 / Math.PI;
            degree += 90;
            if (deltaX < 0) degree += 180;

            var distance = Math.sqrt((gSLeft * gSLeft) + (gSTop * gSTop));
            var gDegree = Math.atan(gSLeft / gSTop) * 180 / Math.PI;
            //if (gSLeft < 0) gDegree += 180;
            if (gSTop <= 0)
                gLeft = sPos.left + (distance * Math.sin((gDegree + this.degree) * Math.PI / 180));
            else
                gLeft = sPos.left + (distance * Math.sin(-1 * (gDegree + this.degree) * Math.PI / 180));
            if (gSTop <= 0)
                gTop = sPos.top - (distance * Math.cos((gDegree + this.degree) * Math.PI / 180));
            else
                gTop = sPos.top + (distance * Math.cos((gDegree + this.degree) * Math.PI / 180));

            gLeft = gLeft / (size * 200) * 100;
            gTop = gTop / (size * 200) * 100;
            this.fireDirected(size, degree, gLeft, gTop);
        }
    }
    
}
function createShipDirectedProjectile(size, degree, left, top) {
    var d = degree || this.degree;
    var x = left || this.left;
    var y = top || this.top;
    var bullet = $("<div class='bullet' />");
    bullet.css({
        transform: "rotate(" + d + "deg)",
        left: numToPer(x), top: numToPer(y),
        width: numToPx(size * .25), height: numToPx(size * 1.5)
    });
    $('.box').prepend(bullet);
    var rads = toRadians(d);
    var top = y - (25 * Math.cos(rads));
    var left = x + (25 * Math.sin(rads));

    var s = this;
    var interval = setInterval(function () {
        if (bullet == undefined) {
            clearInterval(interval);
            return;
        }
            
        var ships = space.shipArray;
        var list;
        var x1, x2, y1, y2, a1, b1;
        //a1 = perToNum(bullet[0].style.left);
        //b1 = perToNum(bullet[0].style.top);
        a1 = bullet.offset().left;
        b1 = bullet.offset().top;
        if (document.elementFromPoint(a1, b1) != null) {
            pointObj = document.elementFromPoint(a1, b1);
            if (pointObj.className.indexOf('ship-block') > -1
                && pointObj.className.indexOf('red') < 0
                && pointObj.className.indexOf('box') < 0
                && pointObj.parentElement.className.indexOf('active') < 0)
            {
                pointObj.className += ' red';
                $(pointObj).remove();
                bullet.remove();
                bullet = undefined;
            }
        }
    }, 5);

    setTimeout(function () {
        if (bullet == undefined) return;
        bullet.css({ "left": left + "%", "top": top + "%" });
        setTimeout(function () {
            if (bullet == undefined) return;
            bullet.remove();
            bullet = undefined;
        }, 1000);
    }, 25);
}

function ship(shipName, shipSize) {
    var s = this;
    s.start = new block("ship-start");
    s.blocks = new blockList();
    s.shipId = shipName;
    s.start.dom.attr('id', shipName);
    s.start.style({ width: numToPx(shipSize), height: numToPx(shipSize) });
    s.blocks.push(this.start);
    s.addSpots(0, 0);
}
ship.prototype.degree = 0;
ship.prototype.left = 0;
ship.prototype.top = 0;
ship.prototype.loadBlocks = loadShipBlocks;
ship.prototype.loadBox = loadShipBox;
ship.prototype.newBlock = newShipBlock;
ship.prototype.addSpot = newSpotBlock;
ship.prototype.addSpots = newSpotBlocks;
ship.prototype.getBlockFromDiv = getShipBlockFromHtml;
ship.prototype.spotToBlock = changeSpotToBlock;
ship.prototype.blockChange = changeShipBlock;
ship.prototype.moveLeft = moveShipLeft;
ship.prototype.moveRight = moveShipRight;
ship.prototype.moveUp = moveShipUp;
ship.prototype.moveDown = moveShipDown;
ship.prototype.fire = createShipProjetile;
ship.prototype.fireDirected = createShipDirectedProjectile;

/* ========================================================================
                                Game
   ======================================================================== */


function newGameShip(func, data, load) {
    var obj = func(data.id, this.zIndex);
    obj.left = data.left || 0;
    obj.top = data.top || 0;
    obj.degree = data.degree || 0;
    if(load == undefined || load) obj.loadBox();
    this.addShip(obj);
    return obj;
}
function getShipBlocks(obj) {
    var list = obj.blocks.list;
    var className = "";
    var j = 0;
    var nBl = [];
    for (var i = 1; i < list.length; i++) {
        if (!list[i].hasCss('ship-spot')) {
            nBl[j] = { x: list[i].x, y: list[i].y };
            className = list[i].getCss().replace('ship-part ship-block', '').trim();
            if (className != '') nBl[j].c = className;
            j++;
        }
    }
    return nBl;
}
function getShipBlocksString(obj) {
    var list = this.getBlocks(obj);
    var str = ["["];
    var item = {};
    var len = list.length;
    for (var i = 0; i < len; i++) {
        item = list[i];
        str.push('{x:', item.x, ',y:', item.y);
        if (item.c != undefined) str.push(',c:', item.c);
        str.push('}');
        if (i + 1 == len) str.push(',');
    }
    str.push("]");
    return str.join();
}
function addGameShip(obj) { this.shipList[obj.shipId] = obj; this.shipArray.push(obj); }
function getGameShip(id) { return this.shipList[id]; }
function selectGameShip(obj) { this.ship.start.removeCss('active'); this.ship = obj; obj.start.addCss('active'); }
function createGameProjetile(obj) {
    this.spacebar = false;
    //var bullet = $("<div class='bullet' />");
    //bullet.css({
    //    "transform": "rotate(" + obj.degree + "deg)",
    //    left: numToPer(obj.left), top: numToPer(obj.top),
    //    width: numToPx(this.zIndex * .25), height: numToPx(this.zIndex * 1.5)
    //});
    //$('.box').prepend(bullet);
    //var rads = toRadians(obj.degree);
    //var top = obj.top - (25 * Math.cos(rads));
    //var left = obj.left + (25 * Math.sin(rads));
    //setTimeout(function () {
    //    bullet.css({ "left": left + "%", "top": top + "%" });
    //    setTimeout(function () {
    //        bullet.remove();
    //        bullet = undefined;
    //    }, 1000);
    //}, 25);
    //this.projectiles.push();
    obj.fireDirected(this.zIndex);
}
function setGameCode(code, value) {
    switch (code) {
        case 32: if (!value) this.spacebar = true; return;
        case 37: this.left = value; return;
        case 65: this.left = value; return;
        case 38: this.up = value; return;
        case 87: this.up = value; return;
        case 39: this.right = value; return;
        case 68: this.right = value; return;
        case 40: this.down = value; return;
        case 83: this.down = value; return;
    }
}
function centerGameShip() {
    if (this.centerLock) return;
    this.centerLock = true;
    var boxSize = this.zIndex * 200;
    var shipOffset = this.ship.start.dom.offset();
    var x = shipOffset.left;
    var y = shipOffset.top;

    var centerX = ($(window).width() / 2);
    var centerY = ($(window).height() / 2);

    var difX = x - centerX; 
    var difY = y - centerY;

    this.boxLeft -= 100 * difX / boxSize;
    this.boxUp -= 100 * difY / boxSize;

    $('.box').css({ "left": numToPer(this.boxLeft), "margin-top": numToPer(this.boxUp) });

    var g = this;
    setTimeout(function () { g.centerLock = false; }, 100);
}
function zoomGame(delta) {
    if (this.zoomLock) return;
    this.zoomLock = true;
    this.zIndex = Math.max(5, Math.min(30, this.zIndex + delta));

    var boxSize = numToPx(this.zIndex * 200);
    var shipSize = numToPx(this.zIndex);
    $('.ship-start').css({ width: shipSize, height: shipSize });
    $('body, .box').css({ width: boxSize, height: boxSize });
    $('.bullet').css({ width: numToPx(this.zIndex * .25), height: numToPx(this.zIndex * 1.5) });
    //var nBlocks = 10 * this.zIndex;
    //var shipOffset = this.ship.start.dom.offset();

    //var valueNeg = shipOffset.top - nBlocks;
    //var valuePos = shipOffset.top - ($(window).height() - nBlocks);
    //if (valueNeg < 0)
    //    this.boxUp += 100(valueNeg / pxToNum(boxSize));
    //else if (valuePos > 0)
    //    this.boxUp += 100(valuePos / pxToNum(boxSize));
    
    //valueNeg = shipOffset.left - nBlocks;
    //valuePos = shipOffset.left - ($(window).width() - nBlocks);
    //if (valueNeg < 0)
    //    this.boxLeft += 100(valueNeg / pxToNum(boxSize));
    //else if (valuePos > 0)
    //    this.boxLeft += 100(valuePos / pxToNum(boxSize));
    //$('.box').css({ "left": numToPer(this.boxLeft), "margin-top": numToPer(this.boxUp) });

    this.centerShip();
    //var g = this;
    //setTimeout(function () { g.centerShip(); }, 100);
    
    var g = this;
    setTimeout(function () { g.zoomLock = false; }, 100);

    return false;
}
function boxMoveUp() {
    var rads = toRadians(this.ship.degree);
    var nBlocks = 20 * this.zIndex;
    var xValue = (Math.sin(rads) * 1.5);
    var yValue = (Math.cos(rads) * 1.5);
    var shipOffset = this.ship.start.dom.offset();
    if (shipOffset.top < nBlocks && yValue > 0) this.boxUp += yValue;
    else if (shipOffset.top > $(window).height() - nBlocks && yValue < 0) this.boxUp += yValue;
    if (shipOffset.left < nBlocks && xValue < 0) this.boxLeft -= xValue;
    else if (shipOffset.left > $(window).width() - nBlocks && xValue > 0) this.boxLeft -= xValue;
    $('.box').css({ "left": numToPer(this.boxLeft), "margin-top": numToPer(this.boxUp) });
    this.ship.moveUp();
}
function boxMoveDown() {
    var rads = toRadians(this.ship.degree);
    var nBlocks = 20 * this.zIndex;
    var xValue = (Math.sin(rads) * 1.5);
    var yValue = (Math.cos(rads) * 1.5);
    var shipOffset = this.ship.start.dom.offset();
    if (shipOffset.top < nBlocks && yValue < 0) this.boxUp -= yValue;
    else if (shipOffset.top > $(window).height() - nBlocks && yValue > 0) this.boxUp -= yValue;
    if (shipOffset.left < nBlocks && xValue > 0) this.boxLeft += xValue;
    else if (shipOffset.left > $(window).width() - nBlocks && xValue < 0) this.boxLeft += xValue;
    $('.box').css({ "left": numToPer(this.boxLeft), "margin-top": numToPer(this.boxUp) });
    this.ship.moveDown();
}
function loadGameArea() { }

function game(func, data) {
    var g = this;
    this.shipList = [];
    this.shipArray = [];
    this.projectiles = [];
    
    g.loop = function () {
        if (g.spacebar) { g.createProjectile(g.ship); }
        if (g.up && !g.down) g.moveUp();
        if (!g.up && g.down) g.moveDown();
        if (g.right && !g.left) g.ship.moveRight();
        if (!g.right && g.left) g.ship.moveLeft();
        setTimeout(g.loop, 100);
    }

    /* Initialize */
    data.left = 10; data.top = 10;
    this.ship = this.newShip(func, data, false);
    var gameShip = this.ship;
    gameShip.start.addCss('active');
    gameShip.start.style({ "left": 10 + "%", "top": 10 + "%" });
    $('.box').append(gameShip.start.dom);
    this.centerShip();
}
game.prototype.zIndex = shipPartWidth;
game.prototype.boxUp = 0;
game.prototype.boxLeft = 0;
game.prototype.up = false;
game.prototype.left = false;
game.prototype.right = false;
game.prototype.down = false;
game.prototype.spacebar = false;
game.prototype.zoomLock = false;
game.prototype.centerLock = false;
game.prototype.getBlocks = getShipBlocks;
game.prototype.getBlocksString = getShipBlocksString;
game.prototype.newShip = newGameShip;
game.prototype.addShip = addGameShip;
game.prototype.getShip = getGameShip;
game.prototype.selectShip = selectGameShip;
game.prototype.createProjectile = createGameProjetile;
game.prototype.setCode = setGameCode;
game.prototype.loadArea = loadGameArea;
game.prototype.zoom = zoomGame;
game.prototype.moveUp = boxMoveUp;
game.prototype.moveDown = boxMoveDown;
game.prototype.centerShip = centerGameShip;